import {hashString} from '../../utils';
import {BaseModel} from './baseModel';

export interface Card {
  cardNumber: string;
  cardType: string; // Credit |
  issuer: string;
  issuerCountry: string;
  scheme: string; //Visa |
  isBind: number;
  createdAt: number;
  userName: string; // hash(scheme+cardNumber)
}

export interface CardWithAddress extends Card {
  solanaAddress: string;
}

export class CardModel extends BaseModel {
  async createTable(): Promise<void> {
    try {
      const db = await BaseModel.getDB();
      const query = `
            CREATE TABLE IF NOT EXISTS card (
                card_number TEXT NOT NULL PRIMARY KEY,
                user_name TEXT NOT NULL,
                card_type TEXT NOT NULL,
                issuer TEXT,
                issuer_country TEXT,
                scheme TEXT NOT NULL,
                is_bind INTEGER NOT NULL DEFAULT 0,
                created_at INTEGER NOT NULL
            );
        `;
      await db.executeSql(query);
    } catch (error) {
      console.log('create table error', error);
    }
  }

  async dropTable(): Promise<void> {
    const db = await BaseModel.getDB();
    await db.executeSql('DROP TABLE IF EXISTS card;');
  }

  async getByCardNumber(cardNumber: string): Promise<Card | null> {
    const db = await BaseModel.getDB();
    const query =
      'select card_number as cardNumber, user_name as userName, card_type as cardType, issuer, issuer_country as issuerCountry, scheme, is_bind as isBind,  created_at as createdAt  from card where card_number = ?';
    const [results] = await db.executeSql(query, [cardNumber]);
    const cards = results.rows.raw() as Card[];
    return cards.length > 0 ? cards[0] : null;
  }

  async getByUserName(userName: string): Promise<Card | null> {
    const db = await BaseModel.getDB();
    const query =
      'select card_number as cardNumber, user_name as userName, card_type as cardType, issuer, issuer_country as issuerCountry, scheme, is_bind as isBind,  created_at as createdAt  from card where user_name = ?';
    const [results] = await db.executeSql(query, [userName]);
    const cards = results.rows.raw() as Card[];
    return cards.length > 0 ? cards[0] : null;
  }

  async getAllBindCard(): Promise<Card[]> {
    const db = await BaseModel.getDB();
    const query =
      'select card_number as cardNumber, user_name as userName, card_type as cardType, issuer, issuer_country as issuerCountry, scheme, is_bind as isBind, created_at as createdAt  from card where is_bind = 1';
    const [results] = await db.executeSql(query);
    const cards = results.rows.raw() as Card[];
    return cards;
  }

  async getAll(): Promise<Card[]> {
    const db = await BaseModel.getDB();
    const query =
      'select card_number as cardNumber, user_name as userName, card_type as cardType, issuer, issuer_country as issuerCountry, scheme, is_bind as isBind, created_at as createdAt from card';
    const [results] = await db.executeSql(query);
    const cards = results.rows.raw() as Card[];
    return cards;
  }

  async deleteCard(card: Card): Promise<void> {
    const db = await BaseModel.getDB();
    const query = 'delete from card where card_number = ?';
    await db.executeSql(query, [card.cardNumber]);
  }

  async deleteByCardNumber(cardNumber: string): Promise<void> {
    const db = await BaseModel.getDB();
    const query = 'delete from card where card_number = ?';
    await db.executeSql(query, [cardNumber]);
  }

  static getCreatedAt(): number {
    return new Date().getTime();
  }

  async insert(card: Card): Promise<number> {
    const db = await BaseModel.getDB();
    const query =
      'insert into card (card_number, card_type, issuer, issuer_country, scheme, is_bind, created_at, user_name) values(?, ?, ?, ?, ?, ?, ?, ?)';
    const result = await db.executeSql(query, [
      card.cardNumber,
      card.cardType,
      card.issuer,
      card.issuerCountry,
      card.scheme,
      card.isBind,
      card.createdAt,
      card.userName,
    ]);
    return result[0].insertId;
  }

  async update(card: Card): Promise<void> {
    const db = await BaseModel.getDB();
    const query =
      'update card set card_type = ?, issuer = ?, issuer_country = ?, scheme = ?, is_bind = ?, user_name = ? where card_number = ?';
    await db.executeSql(query, [
      card.cardType,
      card.issuer,
      card.issuerCountry,
      card.scheme,
      card.isBind,
      card.userName,
      card.cardNumber,
    ]);
  }

  async save(card: Card): Promise<void> {
    const tmpCard = await this.getByCardNumber(card.cardNumber);
    if (tmpCard != null) {
      await this.update(card);
    } else {
      await this.insert(card);
    }
  }

  async updateBindStatus(userName: string, status: number): Promise<void> {
    const db = await BaseModel.getDB();
    const query = 'update card set is_bind = ? where user_name = ?';
    await db.executeSql(query, [status, userName]);
  }

  async unbind(userName: string): Promise<void> {
    const db = await BaseModel.getDB();
    db.transaction(
      tx => {
        tx.executeSql('delete from identity where uid = ?', [userName]);
        tx.executeSql('delete from user where user_name = ?', [userName]);
        tx.executeSql('delete from card where user_name = ?', [userName]);
      },
      error => {},
      () => {},
    );
  }

  async getAllBindWithAddress(): Promise<CardWithAddress[]> {
    const db = await BaseModel.getDB();
    const query =
      'select card.card_number as cardNumber, card.user_name as userName, card.card_type as cardType, card.issuer, card.issuer_country as issuerCountry, card.scheme, card.is_bind as isBind, card.created_at as createdAt, user.solana_address as solanaAddress from card inner join user on card.user_name = user.user_name where card.is_bind = 1';
    const [results] = await db.executeSql(query);
    const cards = results.rows.raw() as CardWithAddress[];
    return cards;
  }

  async getTotalNumber(): Promise<Number> {
    const db = await BaseModel.getDB();
    const query =
      'select count(card_number) as total from card where is_bind = 1';
    const [results] = await db.executeSql(query);
    const result = results.rows.raw()[0];

    return result['total'];
  }
}
